#include <iostream>
#include <string>
#include <cstring>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
using namespace std;

typedef struct request
{
  int left;
  int right;
  char op; 
}request_t;

typedef struct response
{
  int code;
  int result;
}response_t;

void* Routine(void* arg)
{
	pthread_detach(pthread_self()); //分离线程
	int sock = *(int*)arg;
	delete (int*)arg;
	
	while (true){
		request_t rq;
		ssize_t size = recv(sock, &rq, sizeof(rq), 0);
		if (size > 0){
			response_t rp = { 0, 0 };
			switch (rq.op){
			case '+':
				rp.result = rq.left + rq.right;
				break;
			case '-':
				rp.result = rq.left - rq.right;
				break;
			case '*':
				rp.result = rq.left * rq.right;
				break;
			case '/':
				if (rq.right == 0){
					rp.code = 1; //除0错误
				}
				else{
					rp.result = rq.left / rq.right;
				}
				break;
			case '%':
				if (rq.right == 0){
					rp.code = 2; //模0错误
				}
				else{
					rp.result = rq.left % rq.right;
				}
				break;
			default:
				rp.code = 3; //非法运算
				break;
			}
			send(sock, &rp, sizeof(rp), 0);
		}
		else if (size == 0){
			cout << "service done" << endl;
			break;
		}
		else{
			cerr << "read error" << endl;
			break;
		}
	}
	close(sock);
	return nullptr;
}




int main(int argc , char* argv[])
{
  if (argc != 2) 
  {
    cout << "usage error" << endl; 
    exit(1);
  }

  // port socket                 
  int port = atoi(argv[1]);
  int listen_sock = socket(AF_INET , SOCK_STREAM , 0);
  if (listen_sock < 0)
  {
    cout << "socket error" << endl ; 
    exit(2);
  }
  struct sockaddr_in local;
  memset(&local , 0 , sizeof(local)); 
  local.sin_family = AF_INET; 
  local.sin_port = htons(port);
  local.sin_addr.s_addr = htonl(INADDR_ANY);


  if (bind(listen_sock , (struct sockaddr*)&local , sizeof(local)) < 0)
  {
    cout << "bind error" << endl; 
    exit(3);
  }

  if (listen(listen_sock , 5) < 0)
  {
    cout << "listen error" << endl; 
    exit(4);
  }


  struct sockaddr_in peer;
  memset(&peer , '\0' , sizeof(peer));
  socklen_t len;
  for(;;)
  {
    int sock = accept(listen_sock , (struct sockaddr*)&peer , &len);
    if (sock < 0)
    {
      cout << "accept error" << endl;
      continue; // do not stop 
    }

    pthread_t tid;
    int* p = new int(sock);
    pthread_create(&tid , nullptr , Routine, (void*)p);
  }

  return 0;
}
